//配置
const CONFIG = {
  KW: {
    r: 5,
    type: 'KW',
    name: '口温',
    offsetX: 0,
    offsetY: 0,
    color: '#3893ff'
  },
  EW: {
    w: 11,
    h: 11,
    type: 'EW',
    name: '耳温',
    offsetX: 5.5,
    offsetY: 5.5,
    color: '#3893ff'
  },
  YW: {
    w: 8,
    h: 8,
    type: 'YW',
    name: '腋温',
    offsetX: 4,
    offsetY: 4,
    color: '#3893ff'
  },
  GW: {
    r: 9,
    type: 'GW',
    name: '肛温',
    offsetX: 0,
    offsetY: 0,
    color: '#000'
  },
  JW: {
    r: 9,
    type: 'JW',
    name: '降温方式',
    offsetX: 0,
    offsetY: 0,
    color: '#f00'
  },
  MB: {
    r: 10,
    type: 'MB',
    name: '脉搏',
    offsetX: 0,
    offsetY: 0,
    color: '#f00'
  },
  XL: {
    r: 9,
    type: 'XL',
    name: '心率',
    offsetX: 0,
    offsetY: 0,
    color: '#f00'
  },
  TT: {
    w: 9,
    h: 9,
    type: 'TT',
    name: '疼痛',
    offsetX: 4.5,
    offsetY: 8.5,
    color: '#000'
  },
  HX: {
    r: 2,
    type: 'HX',
    name: '呼吸',
    offsetX: 0,
    offsetY: 0,
    color: '#00f'
  }
}
export function CanvasFunc() {
  //画布实例
  this.dom = null
  this.ctx = null
  this.width = null
  this.height = null

  //温度数组
  this.tempArr = []
  //脉搏心率数组
  this.XLArr = []
  //疼痛数组
  this.TTArr = []
  //存放当前页面画出的文字，用于最后一个列多个文字时往前挤，目前只能移3个
  this.txtArr = []

  //创建实例
  this.init = function (dom) {
    this.ctx = null
    this.dom = dom
    this.ctx = dom.getContext('2d')
    this.ctx.width = dom.width
    this.ctx.height = dom.height
  }

  //
  /**
   * 格式化数据
   * @param {String,Number} value 需要格式化的值
   * @returns 数字
   */
  this.formatVal = function (value) {
    return typeof value === 'string' ? value.replace(/[^0-9.]/gi, '') : value
  }

  /**
   * 画口温
   * @param {Number} x 时间轴对应的序号，从0开始
   * @param {String} value 值
   * @param {Boolean} lineBool 是否连线
   */
  this.KW = function (x = 0, value = '42', lineBool = true) {
    //获取值
    const val = this.formatVal(value)
    //定义中心点
    const beginX = 20 * x + 9.5,
      beginY = (42 - (val > 42 ? 42 : val)) * 100 + 0.5
    //画图形
    //小于35℃时显示不升
    if (val < 35) {
      this.TXT('不升', x, 7 * 5 + 2, '#f00', false)
      this.tempArr.push({
        type: 'KW',
        position: [beginX, beginY],
        x,
        value,
        lineBool: false //是否连线
      })
      return
    }
    this.ctx.beginPath()
    this.ctx.fillStyle = CONFIG['KW'].color
    this.ctx.arc(beginX, beginY, CONFIG['KW'].r, 0, 2 * Math.PI)
    this.ctx.fill()
    //画线
    if (lineBool) {
      this.LINE('KW', value, x, beginX, beginY)
    }
  }

  /**
   * 画图例的口温
   * @param {Number} x
   */
  this.KWLegend = function (x = 0) {
    //画图形
    this.ctx.beginPath()
    this.ctx.fillStyle = CONFIG['KW'].color
    this.ctx.arc(x, 9, CONFIG['KW'].r, 0, 2 * Math.PI)
    this.ctx.fill()
  }

  /**
   * 画耳温
   * @param {Number} x 时间轴对应的序号，从0开始
   * @param {String} value 值
   * @param {Boolean} lineBool 是否连线
   */
  this.EW = function (x = 1, value = '37.5', lineBool = true) {
    //获取值
    const val = this.formatVal(value)
    //获取配置
    const obj = CONFIG['EW']
    //定义起点
    const beginX = 20 * x + 9.5 - obj.w / 2,
      beginY = (42 - (val > 42 ? 42 : val)) * 100 + 0.5 + 5 - obj.h / 2
    //画图形
    //小于35℃时显示不升
    if (val < 35) {
      this.TXT('不升', x, 7 * 5 + 2, '#f00', false)
      this.tempArr.push({
        type: 'EW',
        position: [beginX, beginY],
        x,
        value,
        lineBool: false //是否连线
      })
      return
    }
    this.ctx.strokeStyle = CONFIG['YW'].color
    this.ctx.beginPath()
    this.ctx.fillStyle = obj.color
    this.ctx.moveTo(beginX + obj.w / 2, beginY - obj.h / 2)
    this.ctx.lineTo(beginX + obj.w, beginY + obj.h / 2)
    this.ctx.lineTo(beginX, beginY + obj.h / 2)
    this.ctx.lineTo(beginX + obj.w / 2, beginY - obj.h / 2)
    this.ctx.stroke()
    //画线
    if (lineBool) {
      this.LINE('EW', value, x, beginX, beginY, CONFIG['YW'].color)
    }
  }

  /**
   * 画图例的耳温
   * @param {Number} x
   */
  this.EWLegend = function (x = 0) {
    //定义中心点
    //获取配置
    const obj = CONFIG['EW']
    const beginY = 9
    //画图形
    this.ctx.beginPath()
    this.ctx.strokeStyle = obj.color
    this.ctx.moveTo(x + obj.w / 2, beginY - obj.h / 2)
    this.ctx.lineTo(x + obj.w, beginY + obj.h / 2)
    this.ctx.lineTo(x, beginY + obj.h / 2)
    this.ctx.lineTo(x + obj.w / 2, beginY - obj.h / 2)
    this.ctx.stroke()
  }

  /**
   * 画腋温
   * @param {Number} x 时间轴对应的序号，从0开始
   * @param {String} value 值
   * @param {Boolean} lineBool 是否连线
   */
  this.YW = function (x = 1, value = '37.5', lineBool = true) {
    //获取值
    const val = this.formatVal(value)
    //获取配置
    const obj = CONFIG['YW']
    //定义起点
    const beginX = 20 * x + 9.5 - obj.w / 2,
      beginY = (42 - (val > 42 ? 42 : val)) * 100 + 0.5 - obj.h / 2
    //画图形
    //小于35℃时显示不升
    if (val < 35) {
      this.TXT('不升', x, 7 * 5 + 2, '#f00', false)
      this.tempArr.push({
        type: 'YW',
        position: [beginX, beginY],
        x,
        value,
        lineBool: false //是否连线
      })
      return
    }
    this.ctx.strokeStyle = CONFIG['YW'].color
    this.ctx.beginPath()
    this.ctx.moveTo(beginX, beginY)
    this.ctx.lineTo(beginX + obj.w, beginY + obj.h)
    this.ctx.moveTo(beginX + obj.w, beginY)
    this.ctx.lineTo(beginX, beginY + obj.h)
    this.ctx.stroke()
    //画线
    if (lineBool) {
      this.LINE('YW', value, x, beginX, beginY, CONFIG['YW'].color)
    }
  }

  /**
   * 画图例的腋温
   * @param {Number} x
   */
  this.YWLegend = function (x = 0) {
    //画图形
    const obj = CONFIG['YW']
    const beginY = 6
    this.ctx.beginPath()
    this.ctx.moveTo(x, beginY)
    this.ctx.lineTo(x + obj.w, beginY + obj.h)
    this.ctx.moveTo(x + obj.w, beginY)
    this.ctx.lineTo(x, beginY + obj.h)
    this.ctx.stroke()
  }

  /**
   * 画肛温
   * @param {Number} x 时间轴对应的序号，从0开始
   * @param {String} value 值
   * @param {Boolean} lineBool 是否连线
   */
  this.GW = function (x = 1, value = '37.5', lineBool = true) {
    //获取值
    const val = this.formatVal(value)
    //定义中心点
    const beginX = 20 * x + 9.5,
      beginY = (42 - (val > 42 ? 42 : val)) * 100 + 0.5
    //画图形
    //小于35℃时显示不升
    if (val < 35) {
      this.TXT('不升', x, 7 * 5 + 2, '#f00', false)
      this.tempArr.push({
        type: 'GW',
        position: [beginX, beginY],
        x,
        value,
        lineBool: false //是否连线
      })
      return
    }
    this.ctx.strokeStyle = CONFIG['GW'].color
    this.ctx.beginPath()
    this.ctx.arc(beginX, beginY, CONFIG['GW'].r / 2, 0, 2 * Math.PI)
    this.ctx.moveTo(beginX, beginY)
    this.ctx.arc(beginX, beginY, 1, 0, 2 * Math.PI)
    this.ctx.stroke()
    //画线
    if (lineBool) {
      this.LINE('GW', value, x, beginX, beginY, '#3893ff')
    }
  }

  /**
   * 画图例的肛温
   * @param {Number} x
   */
  this.GWLegend = function (x = 0) {
    //画图形
    this.ctx.strokeStyle = CONFIG['GW'].color
    this.ctx.beginPath()
    this.ctx.arc(x, 9, CONFIG['GW'].r / 2, 0, 2 * Math.PI)
    this.ctx.moveTo(x, 9)
    this.ctx.arc(x, 9, 1, 0, 2 * Math.PI)
    this.ctx.stroke()
  }

  //
  /**
   * 画降温方式
   * @param {Number} x 时间轴对应的序号，从0开始
   * @param {String} value 值
   */
  this.JW = function (x = 1, value = '37.5') {
    //获取值
    const val = this.formatVal(value)
    //定义中心点
    const beginX = 20 * x + 9.5,
      beginY = (42 - val) * 100 + 0.5
    //获取该列对应的温度，用于连线
    const _arr = this.tempArr.filter(res => res.x == x)
    if (_arr.length <= 0 || _arr[0].lineBool == false) {
      return
    }
    this.ctx.save()
    this.ctx.beginPath()
    this.ctx.strokeStyle = CONFIG['JW'].color
    this.ctx.setLineDash([5, 3])
    this.ctx.moveTo(
      _arr[0].position[0] + CONFIG[_arr[0].type].offsetX,
      _arr[0].position[1] + CONFIG[_arr[0].type].offsetX
    )
    this.ctx.lineTo(beginX, beginY)
    this.ctx.stroke()
    this.ctx.restore()
    //画图形
    this.ctx.save()
    this.ctx.strokeStyle = CONFIG['JW'].color
    this.ctx.beginPath()
    this.ctx.arc(beginX, beginY, CONFIG['JW'].r / 2, 0, 2 * Math.PI)
    this.ctx.stroke()
    this.ctx.restore()
    switch (_arr[0].type) {
      case 'KW':
      case 'EW':
        this[_arr[0].type](_arr[0].x, _arr[0].value, false)
        break
      case 'GW':
        this.clearArcFun(
          _arr[0].position[0],
          _arr[0].position[1],
          CONFIG['XL'].r / 2
        )
        break
    }
  }

  /**
   * 画脉搏
   * @param {Number} x 时间轴对应的序号，从0开始
   * @param {String} value 值
   * @param {Boolean} lineBool 是否连线
   */
  this.MB = function (x = 4, value = '170', lineBool = true) {
    //获取值
    const val = this.formatVal(value)
    if (val < 20 || val > 180) {
      return
    }
    //定义中心点
    const beginX = 20 * x + 9.5,
      beginY = (180 - val) * 5 + 0.5
    //画图形
    this.ctx.beginPath()
    this.ctx.strokeStyle = '#000'
    this.ctx.fillStyle = CONFIG['MB'].color
    this.ctx.arc(beginX, beginY, CONFIG['MB'].r / 2, 0, 2 * Math.PI)
    this.ctx.fill()
    //画线
    if (lineBool) {
      this.LINE(
        'MB',
        value,
        x,
        beginX,
        beginY,
        CONFIG['MB'].color,
        this.XLArr,
        false
      )
    }
  }

  /**
   * 画图例的脉搏
   * @param {Number} x
   */
  this.MBLegend = function (x = 0) {
    //定义中心点
    //画图形
    this.ctx.beginPath()
    this.ctx.strokeStyle = '#000'
    this.ctx.fillStyle = CONFIG['MB'].color
    this.ctx.arc(x, 9, CONFIG['MB'].r / 2, 0, 2 * Math.PI)
    this.ctx.fill()
  }

  /**
   * 画心率
   * @param {Number} x 时间轴对应的序号，从0开始
   * @param {String} value 值
   * @param {Boolean} lineBool 是否连线
   */
  this.XL = function (x = 4, value = '170', lineBool = true) {
    //获取值
    const val = this.formatVal(value)
    if (val < 20 || val > 180) {
      return
    }
    //定义中心点
    const beginX = 20 * x + 9.5,
      beginY = (180 - val) * 5 + 0.5

    // //如果当前列有脉搏，那么连线
    const arr2 = this.XLArr.filter(res => res.x === x)
    if (arr2.length > 0) {
      this.ctx.save()
      this.ctx.beginPath()
      this.ctx.moveTo(beginX, beginY)
      this.ctx.strokeStyle = CONFIG['XL'].color
      this.ctx.lineTo(arr2[0].position[0], arr2[0].position[1])
      this.ctx.stroke()
      this.ctx.restore()
    }

    //画图形
    this.ctx.strokeStyle = CONFIG['XL'].color
    this.ctx.beginPath()
    this.ctx.arc(beginX, beginY, CONFIG['XL'].r / 2, 0, 2 * Math.PI)
    this.ctx.stroke()
    //画线
    if (lineBool) {
      this.LINE('XL', value, x, beginX, beginY, CONFIG['XL'].color, this.XLArr)
    }
    if (!lineBool) {
      this.XLArr.push({
        type: 'XL',
        position: [beginX, beginY],
        x,
        value,
        lineBool: true
      })
    }

    const point = this.XLArr.filter(res => res.x == x && res.value == value)
    // 当该点上没有脉搏，清除中间多余的线
    if (point.length == 0) {
      this.clearArcFun(beginX, beginY, CONFIG['XL'].r / 2)
    }
  }

  /**
   * 画图例的心率
   * @param {Number} x
   */
  this.XLLegend = function (x = 0) {
    //定义中心点
    //画图形
    this.ctx.beginPath()
    this.ctx.strokeStyle = CONFIG['XL'].color
    this.ctx.arc(x, 9, CONFIG['XL'].r / 2, 0, 2 * Math.PI)
    this.ctx.stroke()
  }

  /**
   * 画疼痛
   * @param {Number} x 时间轴对应的序号，从0开始
   * @param {String} value 值
   * @param {Boolean} lineBool 是否连线
   */
  this.TT = function (x = 0, value = '1', lineBool = true) {
    //获取值
    const val =
      typeof value === 'string' ? value.replace(/[^0-9.]/gi, '') : value
    const obj = CONFIG['TT']
    //定义中心点
    const beginX = 20 * x + 10 - obj.w / 2,
      beginY = 800 + (10 - val) * 10 - obj.h / 2 - 3
    //画图形
    this.ctx.beginPath()
    this.ctx.fillStyle = obj.color
    this.ctx.moveTo(beginX, beginY)
    this.ctx.lineTo(beginX + obj.w, beginY)
    this.ctx.lineTo(beginX + obj.w / 2, beginY + obj.h)
    this.ctx.closePath()
    this.ctx.fill()
    this.ctx.strokeStyle = '#000'
    //画线
    if (lineBool) {
      this.LINE(
        'TT',
        value,
        x,
        beginX,
        beginY,
        CONFIG['TT'].color,
        this.TTArr,
        true
      )
    }
  }

  /**
   * 画图例的疼痛
   * @param {Number} x
   */
  this.TTLegend = function (x = 0) {
    //画图形
    const obj = CONFIG['TT']
    const beginY = 5
    this.ctx.beginPath()
    this.ctx.fillStyle = obj.color
    this.ctx.moveTo(x, beginY)
    this.ctx.lineTo(x + obj.w, beginY)
    this.ctx.lineTo(x + obj.w / 2, beginY + obj.h)
    this.ctx.closePath()
    this.ctx.fill()
    this.ctx.strokeStyle = '#000'
  }

  /**
   * 画呼吸
   * @param {Number} x 时间轴对应的序号，从0开始
   * @param {String} value 值
   */
  this.HX = function (x = 0, value = '42') {
    //获取值
    const val = this.formatVal(value)
    //定义中心点
    const beginX = 20 * x + 9.5,
      beginY = (42 - val) * 100 + 0.5
    //画图形
    this.ctx.beginPath()
    this.ctx.strokeStyle = CONFIG['HX'].color
    this.ctx.arc(beginX, beginY, CONFIG['HX'].r, 0, 2 * Math.PI)
    this.ctx.stroke()
  }

  /**
   * 画图例的呼吸
   * @param {Number} x
   */
  this.HXLegend = function (x = 0) {
    //定义中心点
    //画图形
    this.ctx.beginPath()
    this.ctx.strokeStyle = CONFIG['HX'].color
    this.ctx.arc(x, 9, CONFIG['HX'].r, 0, 2 * Math.PI)
    this.ctx.stroke()
  }

  /**
   * 画线
   * @param {String} type 类型，取 "KW"、"YW"" 等
   * @param {String} value 值
   * @param {Number} x 时间轴对应的序号，从0开始
   * @param {Number} beginX 开始x轴坐标点
   * @param {Number} beginY 开始y轴坐标点
   * @param {String} color 线的颜色
   * @param {Array} arr 当前信息存储的数组，也就是画线的数组
   * @param {Boolean} isTT 是否是疼痛
   * @param {Boolean} isLineToPrev 是否只连线上一个，即上一个无值时不连线
   */
  this.LINE = function (
    type,
    value,
    x,
    beginX,
    beginY,
    color,
    arr = this.tempArr,
    isTT = false
  ) {
    this.ctx.lineWidth = 2
    //存储该数据，用于连线
    arr.push({
      type,
      position: [beginX, beginY],
      x,
      value,
      lineBool: true
    })
    const _obj = arr[arr.length - 2]

    //第一个点不画线，前一个lineBool=false也不连线
    if (arr.length >= 2 && _obj && _obj.lineBool === true) {
      this.ctx.save()
      this.ctx.beginPath()
      this.ctx.strokeStyle = color ? color : CONFIG[type].color
      let obj
      //疼痛评分该列有多个数据时需要连线第一个
      if (isTT && x != _obj.x) {
        obj = arr.filter(res => res.x === _obj.x)
        obj = obj[obj.length - 1]
      } else {
        obj = arr[arr.length - 2]
      }
      //画图形
      this.ctx.moveTo(
        obj.position[0] + CONFIG[obj.type].offsetX,
        obj.position[1] + CONFIG[obj.type].offsetY
      )
      this.ctx.lineTo(
        beginX + CONFIG[type].offsetX,
        beginY + CONFIG[type].offsetY
      )
      this.ctx.stroke()
      //清除中间多余的线
      // if (obj.type === 'GW') {
      //   this.clearArcFun(obj.position[0], obj.position[1], CONFIG['XL'].r / 2)
      // }

      // 心率-当该点上没有脉搏，清除中间多余的线
      if (obj.type === 'XL') {
        const point = this.XLArr.filter(
          res => res.x == obj.x && res.value == obj.value
        )
        if (point.length == 0) {
          this.clearArcFun(obj.position[0], obj.position[1], CONFIG['XL'].r / 2)
        }
      }

      this.ctx.restore()
    }
    this.ctx.lineWidth = 1
  }

  /**
   * 画文字，判断当前位置是否已有值
   * @param {String} txt 文字
   * @param {Number} x  时间轴对应的序号，从0开始
   * @param {Number} y  y轴对应的序号，从0开始
   * @param {String} color 字体颜色
   * @param {Boolean} writeIntoArr 是否写进文字数组里，用于当前格子有值时向后挤
   */
  this.TXT = function (
    txt = '',
    x = 0,
    y = 0,
    color = '#f00',
    writeIntoArr = true
  ) {
    //需要写进数组进行位置查重
    if (writeIntoArr) {
      //查看想占的格子上是否已有值
      const isRepeat = this.txtArr.find(
        res => res.position[0] === x && res.position[1] === y
      )
      //当前列已有文字,则放在后面
      if (isRepeat) {
        const obj = this.txtArr[this.txtArr.length - 1]
        y = obj.position[1] + obj.txt.length + 1
      }
    }
    this.TXTDraw(txt, x, y, color)
  }

  /**
   * 实际画文字的方法
   * @param {String} txt1 文字
   * @param {Number} x1 时间轴对应的序号，从0开始
   * @param {Number} y1 y轴对应的序号，从0开始
   * @param {String} color 字体颜色
   */
  this.TXTDraw = function (txt1, x1, y1, color = '#f00') {
    this.ctx.font = '12px Microsoft YaHei'
    this.ctx.save()
    this.ctx.fillStyle = color
    //一个一个文字画
    const txts = txt1.split('')
    for (const i in txts) {
      this.ctx.fillText(txts[i], 20 * x1 + 3.5, 20 * (y1 + 1) - 5 + 20 * i)
    }
    this.txtArr.push({
      position: [x1, y1],
      txt: txt1
    })
    this.ctx.restore()
  }

  /**
   * 画图例
   * @param {String} txt1 文字
   * @param {Number} x1 时间轴对应的序号，从0开始
   * @param {Number} y1 y轴对应的序号，从0开始
   * @param {String} color 字体颜色
   */
  this.TXTLegendDraw = function (txt1, x1, color = '#f00') {
    this.ctx.font = '12px Microsoft YaHei'
    this.ctx.save()
    this.ctx.fillStyle = color
    //一个一个文字画
    this.ctx.fillText(txt1, x1, 14)
    this.ctx.restore()
  }

  //清空画布
  this.clean = function () {
    this.ctx.beginPath()
    this.ctx.clearRect(0, 0, this.ctx.width, this.ctx.height)
    this.tempArr = []
    this.XLArr = []
    this.TTArr = []
    this.txtArr = []
  }
  /**
   * 清除圆
   * @param {Number} x x轴坐标
   * @param {Number} y y轴坐标
   * @param {Number} r 半径
   */
  this.clearArcFun = function (x, y, r) {
    //(x,y)为要清除的圆的圆心，r为半径，cxt为context
    let stepClear = 1 //别忘记这一步
    const { ctx } = this
    clearArc(x, y, r)
    function clearArc(x, y, radius) {
      const calcWidth = radius - stepClear
      const calcHeight = Math.sqrt(radius * radius - calcWidth * calcWidth)

      const posX = x - calcWidth
      const posY = y - calcHeight

      const widthX = 2 * calcWidth
      const heightY = 2 * calcHeight

      if (stepClear <= radius) {
        ctx.clearRect(posX, posY, widthX, heightY)
        stepClear += 1
        clearArc(x, y, radius)
      }
    }
  }
}
